package com.egao.common.module.system.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.egao.common.core.Constants;
import com.egao.common.core.exception.ParameterException;
import com.egao.common.core.web.JsonResult;
import com.egao.common.core.web.PageParam;
import com.egao.common.module.system.constants.DictConstants;
import com.egao.common.module.system.entity.Dict;
import com.egao.common.module.system.mapper.DictMapper;
import com.egao.common.module.system.service.DictService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 字典服务实现类
 *
 * @author lym
 */
@Service
public class DictServiceImpl extends ServiceImpl<DictMapper, Dict> implements DictService {


    private RedisTemplate<String, List<Object>> redisTemplate;

    @Resource
    public void setRedisTemplate(RedisTemplate<String, List<Object>> redisTemplate) {
        RedisSerializer stringSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        this.redisTemplate = redisTemplate;
    }

    @Override
    public List<Dict> listAll(String type, String label) {
        return baseMapper.selectList(
                new QueryWrapper<Dict>()
                        .eq(!StrUtil.isBlank(type), "type", type)
                        .like(!StrUtil.isBlank(label), "label", label)
                        .orderByAsc("type")
                        .orderByAsc("sort")
        );
    }

    @Override
    public List<Dict> listPage(PageParam<Dict> page) {
        return baseMapper.listPage(page);
    }

    @Override
    public List<Dict> listType() {
        return baseMapper.selectList(
                new QueryWrapper<Dict>()
                        .select("type", "description")
                        .groupBy("type")
                        .orderByAsc("type")
        );
    }

    @Override
    public Dict getByTypeAndValue(String type, String value) {
        return baseMapper.selectOne(new QueryWrapper<Dict>()
                .eq("type", type)
                .eq("value", value));
    }

    @Override
    public List<Dict> cacheList(String type) {
        Map<Object, Object> dictMaps = redisTemplate.opsForHash().entries(Constants.DICT_CACHE);
        return cacheList(type, dictMaps);
    }

    @Override
    public String cacheLabel(String type, String value) {
        for (Dict dict : cacheList(type)) {
            if (dict.getValue().equals(value)) {
                return dict.getLabel();
            }
        }
        return "";
    }

    @Override
    public String cacheValue(String type, String label) {
        for (Dict dict : cacheList(type)) {
            if (dict.getLabel().equals(label)) {
                return dict.getValue();
            }
        }
        return "";
    }

    /**
     * saveCache
     * 缓存全部字典
     */
    @Override
    public void saveCache() {
        List<Dict> dictAllList = listAll("", "");
        if (dictAllList == null || dictAllList.size() == 0) {
            return;
        }

        Map<Object, Object> newDictMaps = new HashMap<>();
        String preType = "";
        List<Dict> dictList = new ArrayList<>();
        for (Dict dict : dictAllList) {
            if (StrUtil.isBlank(preType)) {
                preType = dict.getType();
            }
            if (preType.equals(dict.getType())) {
                dictList.add(dict);
            }
            if (!preType.equals(dict.getType())) {
                newDictMaps.put(preType, dictList);
                preType = dict.getType();
                dictList = new ArrayList<>();
                dictList.add(dict);
            }
        }

        redisTemplate.opsForHash().putAll(Constants.DICT_CACHE, newDictMaps);
    }

    @Override
    public Map<String, List<Dict>> cacheMaps(String types) {
        if (StrUtil.isBlank(types)) {
            throw new ParameterException("类型参数为空");
        }

        Map<String, List<Dict>> map = new HashMap<>();
        String[] typeList = types.split(",");
        for (String type : typeList) {
            map.put(type, cacheList(type));
        }
        return map;
    }

    @Override
    public Map<String, List<Dict>> cacheMaps(String[] types) {
        Map<String, List<Dict>> map = new HashMap<>();
        for (String type : types) {
            map.put(StrUtil.toCamelCase(type), cacheList(type));
        }
        return map;
    }

    @Override
    public JsonResult insertDict(Dict dict) {
        if (baseMapper.insert(dict) == 1) {
            return JsonResult.ok("添加字典成功");
        }

        return JsonResult.error("添加字典失败");
    }

    @Override
    public JsonResult updateDict(Dict dict) {
        if (baseMapper.updateById(dict) == 1) {
            return JsonResult.ok("修改字典成功");
        }

        return JsonResult.error("修改字典失败");
    }

    @Override
    public JsonResult dictDelete(Integer id) {
        if (id == null) {
            throw new ParameterException("参数对象为空");
        }

        if (removeById(id)) {
            return JsonResult.ok("删除成功");
        }

        return JsonResult.error("删除失败");
    }

    @Override
    public List<Dict> cacheNatureList(String type) {
        List<Dict> dictList = cacheList(type);
        // 去掉网签单位性质
        return dictList.stream().filter(d -> Integer.parseInt(d.getValue()) < 70).collect(Collectors.toList());
    }

    @Override
    public Map<Object, Object> getCacheDictMaps() {
        return redisTemplate.opsForHash().entries(Constants.DICT_CACHE);
    }

    @Override
    public List<Dict> cacheList(String type, Map<Object, Object> dictMaps) {
        // 字典缓存存在
        if (dictMaps != null && dictMaps.size() > 0) {
            // 获取指定类型缓存
            List<Dict> dictList = (List<Dict>) dictMaps.get(type);

            // 指定类型缓存存在直接返回
            if (dictList != null && dictList.size() > 0) {
                return dictList;
            }

            // 指定类型缓存不存在添加一个新指定类型缓存
            List<Dict> dictSqlList = listAll(type, "");
            Map<String, List<Dict>> map = new HashMap<>();
            map.put(type, dictSqlList);
            redisTemplate.opsForHash().putAll(Constants.DICT_CACHE, map);

            return dictSqlList;
        }

        // 字典缓存不存在 重新缓存全部
        saveCache();

        Map<Object, Object> newDictMaps = redisTemplate.opsForHash().entries(Constants.DICT_CACHE);
        if (newDictMaps == null || newDictMaps.size() == 0) {
            return listAll(type, "");
        }

        return (List<Dict>) newDictMaps.get(type);
    }

    @Override
    public String cacheLabel(String type, String value, Map<Object, Object> dictMaps) {
        for (Dict dict : cacheList(type, dictMaps)) {
            if (dict.getValue().equals(value)) {
                return dict.getLabel();
            }
        }
        return "";
    }

    @Override
    public Dict getByParent(String type, Integer parentId, String value) {
        return baseMapper.selectOne(new QueryWrapper<Dict>()
                .eq("type", type)
                .eq("parent_id", parentId)
                .eq("value", value)
        );
    }

    @Override
    public Map<String, List<Dict>> studentForm() {
        Map<String, List<Dict>> map = new HashMap<>();
        map.put("pyfsDict", cacheList(DictConstants.TYPE_PYFS));
        map.put("cxsydmDict", cacheList(DictConstants.TYPE_CXSYDM));
        map.put("xxfsDict", cacheList(DictConstants.TYPE_XXFS));
        map.put("syszdDict", cacheList(DictConstants.TYPE_SYSZD));
        map.put("zxjhDict", cacheList(DictConstants.TYPE_ZXJH));
        map.put("jzbfdxbzDict", cacheList(DictConstants.TYPE_JZBFDXBZ));
        map.put("knslbDict", cacheList(DictConstants.TYPE_KNSLB));
        map.put("zzmmDict", cacheList(DictConstants.TYPE_ZZMM));
        map.put("mzDict", cacheList(DictConstants.TYPE_MZ));
        map.put("zxwyyzDict", cacheList(DictConstants.TYPE_ZXWYYZ));
        map.put("companyNatureDict", cacheList(DictConstants.COMPANY_NATURE));
        map.put("companyIndustryDict", cacheList(DictConstants.COMPANY_INDUSTRY));
        map.put("yxdwxzDict", cacheList(DictConstants.TYPE_YXDWXZ));
        map.put("yxdwhyDict", cacheList(DictConstants.TYPE_YXDWHY));
        map.put("yxzwlbDict", cacheList(DictConstants.TYPE_YXZWLB));
        map.put("yxyxDict", cacheList(DictConstants.TYPE_YXYX));
        map.put("hksfzrxxDict", cacheList(DictConstants.TYPE_HKSFZRXX));
        map.put("hyzkDict", cacheList(DictConstants.TYPE_HYZK));
        map.put("fxxwDict", cacheList(DictConstants.TYPE_FXXW));
        map.put("bzkxlDict", cacheList(DictConstants.TYPE_BZKXL));
        map.put("bzkccDict", cacheList(DictConstants.TYPE_BZKCC));
        return map;
    }

    @Override
    public void initRedis() {
        List<Dict> dictList = list();
        Map<String, List<Dict>> collect = dictList.stream().collect(Collectors.groupingBy(Dict::getType));
        collect.forEach((key, value) -> {
            Map<String, String> map = new HashMap<>(value.size());
            value.forEach(d -> {
                map.put(d.getLabel(), d.getValue());
            });
            redisTemplate.opsForHash().put("dict", key, map);
        });
    }

    @Override
    public String redisLabel(String type, String value) {
        Object object = redisTemplate.opsForHash().get("dict", type);
        if (object == null) {
            return "";
        }
        Map<String, String> map = (Map<String, String>) object;

        for (String key : map.keySet()) {
            if (map.get(key).equals(value)) {
                return key;
            }
        }
        return "";
    }

    @Override
    public String redisValue(String type, String label) {
        Object object = redisTemplate.opsForHash().get("dict", type);
        if (object == null) {
            return "";
        }
        Map<String, String> map = (Map<String, String>) object;

        for (String key : map.keySet()) {
            if (key.equals(label)) {
                return map.get(key);
            }
        }
        return "";
    }

    @Override
    public List<Dict> redisList(String type) {
        Object object = redisTemplate.opsForHash().get("dict", type);
        if (object == null) {
            return new ArrayList<>();
        }
        Map<String, String> map = (Map<String, String>) object;

        List<Dict> dictList = new ArrayList<>();
        for (String key : map.keySet()) {
            Dict dict = new Dict();
            dict.setType(type);
            dict.setLabel(key);
            dict.setValue(map.get(key));
            dictList.add(dict);
        }
        return dictList;
    }
}
